package org.spindle.soasuite;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spindle.soasuite.controllers.ControllerFactory;
import org.spindle.soasuite.core.api.AExecutable;
import org.spindle.soasuite.core.constants.StateConstants;
import org.spindle.soasuite.core.logging.Log;
import org.spindle.soasuite.core.logging.LogFactory;
import org.spindle.soasuite.datasource.helper.HSQLDBHibernateUtil;
import org.spindle.soasuite.datasource.internal.core.InternalDS;
import org.spindle.soasuite.parser.ParserFactory;
import org.spindle.soasuite.parser.api.IParser;
import org.spindle.soasuite.parser.api.ParserConstants;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class Controller extends HttpServlet {

    private static Log log = LogFactory.getLogger(Controller.class);

    private ControllerFactory coreController;
    private AExecutable executable;
    private IParser parser;
    private String path;
    InternalDS internalDS;

    private Map<String, Object> stateMap = new ConcurrentHashMap<String, Object>();


    @Override
    public void init() throws ServletException {
        super.init();

        coreController = new ControllerFactory();
        internalDS = new InternalDS();
        stateMap.put(StateConstants.INTERNAL_DS, internalDS);
        try {
            coreController.initialize();
        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (ClassNotFoundException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }

        parser = ParserFactory.getParser(ParserConstants.JSON_PARSER);

    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doRequest(request, response);
    }


    private void doRequest(HttpServletRequest request, HttpServletResponse response) {
        Object executableResult;
        String output;
        path = request.getPathInfo();

        log.logInfo("Required path: " + path);

        Boolean authState = (Boolean) stateMap.get("auth");
        if (authState == null) {
            authState = false;
            log.logDebug("Authentification state is null. User not authenticated");
        }

        try {
            PrintWriter out = response.getWriter();
            response.setContentType("text/plain");
            Boolean isEndpoint = path.indexOf("endpoint") != -1;
            if ("/login".equals(path) || authState == true || isEndpoint) {
                executable = coreController.getController(path, stateMap);

                if (executable != null) {
                    log.logDebug("Microcontroller: " + executable.getName());
                    coreController.populateFields(path, executable, request.getParameterMap(), isEndpoint);
                    executableResult = executable.executeController();
                    internalDS.commitTransaction();
                    switch (executable.getReturnType()) {
                        case StateConstants.XML_TYPE:
                            output = executableResult.toString();
                            response.setContentType("application/xml");
                            break;
                        default:
                            output = parser.marshallData(executableResult);
                    }

                    out.print(output);
                    if (authState == true) {
                        request.getSession().setAttribute("auth", true);
                    }
                } else {
                    log.logInfo("There is no microcontroller register for desired path");
                }
            } else {
                request.getSession().setAttribute("auth", false);
                response.setStatus(403);
            }

            out.flush();

        } catch (Exception e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }

    @Override
    public void destroy() {
        super.destroy();    //To change body of overridden methods use File | Settings | File Templates.
        try {
            HSQLDBHibernateUtil.shutdownConnection();
        } catch (SQLException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }


}
